;    t1_test3.asm - basic emulation for 3niti alpha simu1 (updated 26 Nov 2011)
;
;    Part of NedoPC SDK (software development kit for simple devices)
;
;    Copyright (C) 2009-2011, Alexander A. Shabarshin <ashabarshin@gmail.com>
;
;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;    (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.

; -------------------------------------------------------------------------
; v1.0.0 (26 Nov 2011) - initial release

	processor pic16f870
	radix dec
	include "p16f870.inc"
	__CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC
	include "PDBLv1-2A2.inc"

; PORTA - outputs to choose column (A0...A4) and direct LED (A5)
; PORTB - inputs for rows of switches (B0...B5) and I2C (B6,B7)
; PORTC - outputs for rows of LEDs (C0...C5) and RS232 (C6,C7)

;Format of the triad:
;|7|6|5|4|3|2|1|0|
;|+|-|+|-|+|-|+|-|
;|par|low|mid|high
;par (parity) is not yet used, so it's always 00 for now...

; Bank 0

Mode	EQU	0x3C
PC_h	EQU	0x3D ; PC higher triad
PC_m	EQU	0x3E ; PC middle triad
PC_l	EQU	0x3F ; PC lower triad
d_base	EQU	0x40 ; ternary data segment 0x40...0x6F
;d_OOO	EQU	0x40 ; 0
;d_NOO	EQU	0x41 ; -9
;d_POO	EQU	0x42 ; +9
DA_m	EQU	0x43 ; current data segment address (middle part)
;d_ONO	EQU	0x44 ; -3
;d_NNO	EQU	0x45 ; -12
;d_PNO	EQU	0x46 ; +6
DA_h	EQU	0x47 ; current data segment address (higher part)
;d_OPO	EQU	0x48 ; +3
;d_NPO	EQU	0x49 ; -6
;d_PPO	EQU	0x4A ; +12
tmp0	EQU	0x4B
tmp1	EQU	0x4C
tmp2	EQU	0x4D
tmp3	EQU	0x4E
tmp4	EQU	0x4F
;d_OON	EQU	0x50 ; -1
;d_NON	EQU	0x51 ; -10
;d_PON	EQU	0x52 ; +8
cnt1	EQU	0x53
;d_ONN	EQU	0x54 ; -4
;d_NNN	EQU	0x55 ; -13
;d_PNN	EQU	0x56 ; +5
cnt2	EQU	0x57
;d_OPN	EQU	0x58 ; +2
;d_NPN	EQU	0x59 ; -7
;d_PPN	EQU	0x5A ; +11
swit0	EQU	0x5B ; copy of switch row 0
swit1	EQU	0x5C ; copy of switch row 1
swit2	EQU	0x5D ; copy of switch row 2
swit3	EQU	0x5E ; copy of switch row 3
swit4	EQU	0x5F ; copy of switch row 4
;d_OOP	EQU	0x60 ; +1
;d_NOP	EQU	0x61 ; -8
;d_POP	EQU	0x62 ; +10
CA_m	EQU	0x63 ; current code segment address (middle part)
;d_ONP	EQU	0x64 ; -2
;d_NNP	EQU	0x65 ; -11
;d_PNP	EQU	0x66 ; +7
CA_h	EQU	0x67 ; current code segment address (higher part)
;d_OPP	EQU	0x68 ; +4
;d_NPP	EQU	0x69 ; -5
;d_PPP	EQU	0x6A ; +13
F_reg	EQU	0x6B ; Register F (hi:RSF,mid:DPF,lo:BCF)
A_reg	EQU	0x6C ; Register A
B_reg	EQU	0x6D ; Register B
C_reg	EQU	0x6E ; Command to execute
D_reg	EQU	0x6F ; Data to display on LEDs 10,11,12

; Common

mask	EQU	0x7E
count	EQU	0x7F

; Bank 1

DPn_h	EQU	0xA0 ; DPn hifger triad
DPn_m	EQU	0xA1 ; DPn middle triad
DPn_l	EQU	0xA2 ; DPn lower triad
DPo_h	EQU	0xA3 ; DPo higher trida
DPo_m	EQU	0xA4 ; DPo middle triad
DPo_l	EQU	0xA5 ; DPo lower triad
DPp_h	EQU	0xA6 ; DPp higher triad
DPp_m	EQU	0xA7 ; DPp middle triad
DPp_l	EQU	0xA8 ; DPp lower triad

; Reset vector
	ORG 00h
	goto Start

; Interrupt vector
	ORG 04h
	retfie

Start:

; Switch to bank 1
	bsf STATUS,RP0
	bcf STATUS,RP1

; Configure all I/O pins as digital (bank1)
	movlw	0x06
	movwf	ADCON1^0x80

; Set direction of ports (bank1)
	movlw	b'00000000'
	movwf	TRISA^0x80
	movlw	b'00111111'
	movwf	TRISB^0x80
	movlw	b'11000000'
	movwf	TRISC^0x80

; Setup interrupts (bank1)
	clrf	INTCON ; disable all interrupts and clear all flags
	bcf	OPTION_REG^0x80,NOT_RBPU ; enable pull-ups
;	bsf	OPTION_REG,INTEDG ; interrupt on rising edge
;	bcf	OPTION_REG,T0CS ; enable Timer0 in timer mode
;	bcf	OPTION_REG,PSA ; assign prescaler to the Timer0 (1:256)
;	bsf	INTCON,T0IE ; enable Timer0 interrupt
;	bcf	INTCON,INTE ; disable RB0 port change interrupt
;	bsf	INTCON,GIE ; enable interrupts

; Switch to bank 0
	bcf STATUS,RP0
	bcf STATUS,RP1

; Initialize output ports
;	movlw b'11111111'
;	movwf PORTA
;	movwf PORTB
;	movwf PORTC

	goto	Main

tri_switch: ; 7 cycles with call
	decf	count,w ; 5,4,3,2,1
	addwf	PCL,f
	retlw	swit4 ; count=1
	retlw	swit3 ; count=2
	retlw	swit2 ; count=3
	retlw	swit1 ; count=4
	retlw	swit0 ; count=5

tri_add_3trits: ; 6 cycles with call
	addwf	PCL,f ; jump to proper value
	retlw	b'00000000' ; 000000 ->  0+0+0= 0 S=O C=O
	retlw	b'00000001' ; 000001 ->  0+0-1=-1 S=N C=O
	retlw	b'00000010' ; 000010 ->  0+0+1= 1 S=P C=O
	retlw	b'00010000' ; 000011 -> invalid
	retlw	b'00000001' ; 000100 ->  0-1+0=-1 S=N C=O
	retlw	b'00000110' ; 000101 ->  0-1-1=-2 S=P C=N
	retlw	b'00000000' ; 000110 ->  0-1+1= 0 S=O C=O
	retlw	b'00010000' ; 000111 -> invalid
	retlw	b'00000010' ; 001000 ->  0+1+0= 1 S=P C=O
	retlw	b'00000000' ; 001001 ->  0+1-1= 0 S=O C=O
	retlw	b'00001001' ; 001010 ->  0+1+1= 2 S=N C=P
	retlw	b'00010000' ; 001011 -> invalid
	retlw	b'00010000' ; 001100 -> invalid
	retlw	b'00010000' ; 001101 -> invalid
	retlw	b'00010000' ; 001110 -> invalid
	retlw	b'00010000' ; 001111 -> invalid
	retlw	b'00000001' ; 010000 -> -1+0+0=-1 S=N C=O
	retlw	b'00000110' ; 010001 -> -1+0-1=-2 S=P C=N
	retlw	b'00000000' ; 010010 -> -1+0+1= 0 S=O C=O
	retlw	b'00010000' ; 010011 -> invalid
	retlw	b'00000110' ; 010100 -> -1-1+0=-2 S=P C=N
	retlw	b'00000100' ; 010101 -> -1-1-1=-3 S=O C=N
	retlw	b'00000001' ; 010110 -> -1-1+1=-1 S=N C=O
	retlw	b'00010000' ; 010111 -> invalid
	retlw	b'00000000' ; 011000 -> -1+1+0= 0 S=O C=O
	retlw	b'00000001' ; 011001 -> -1+1-1=-1 S=N C=O
	retlw	b'00000010' ; 011010 -> -1+1+1= 1 S=P C=O
	retlw	b'00010000' ; 011011 -> invalid
	retlw	b'00010000' ; 011100 -> invalid
	retlw	b'00010000' ; 011101 -> invalid
	retlw	b'00010000' ; 011110 -> invalid
	retlw	b'00010000' ; 011111 -> invalid
	retlw	b'00000010' ; 100000 ->  1+0+0= 1 S=P C=O
	retlw	b'00000000' ; 100001 ->  1+0-1= 0 S=O C=O
	retlw	b'00001001' ; 100010 ->  1+0+1= 2 S=N C=P
	retlw	b'00010000' ; 100011 -> invalid
	retlw	b'00000000' ; 100100 ->  1-1+0= 0 S=O C=O
	retlw	b'00000001' ; 100101 ->  1-1-1=-1 S=N C=O
	retlw	b'00000010' ; 100110 ->  1-1+1= 1 S=P C=O
	retlw	b'00010000' ; 100111 -> invalid
	retlw	b'00001001' ; 101000 ->  1+1+0= 2 S=N C=P
	retlw	b'00000010' ; 101001 ->  1+1-1= 1 S=P C=O
	retlw	b'00001000' ; 101010 ->  1+1+1= 3 S=O C=P
	retlw	b'00010000' ; 101011 -> invalid
;	retlw	b'00010000' ; 101100 -> invalid
;	retlw	b'00010000' ; 101101 -> invalid
;	retlw	b'00010000' ; 101110 -> invalid
;	retlw	b'00010000' ; 101111 -> invalid
;	retlw	b'00010000' ; 110000 -> invalid
;	retlw	b'00010000' ; 110001 -> invalid
;	retlw	b'00010000' ; 110010 -> invalid
;	retlw	b'00010000' ; 110011 -> invalid
;	retlw	b'00010000' ; 110100 -> invalid
;	retlw	b'00010000' ; 110101 -> invalid
;	retlw	b'00010000' ; 110110 -> invalid
;	retlw	b'00010000' ; 110111 -> invalid
;	retlw	b'00010000' ; 111000 -> invalid
;	retlw	b'00010000' ; 111001 -> invalid
;	retlw	b'00010000' ; 111010 -> invalid
;	retlw	b'00010000' ; 111011 -> invalid
;	retlw	b'00010000' ; 111100 -> invalid
;	retlw	b'00010000' ; 111101 -> invalid
;	retlw	b'00010000' ; 111110 -> invalid
;	retlw	b'00010000' ; 111111 -> invalid

tri_add_test MACRO B
	movlw	B
	call tri_add_3trits
	ENDM

; Ternary adder W+A_reg+BCF=A_reg and BCF (used tmp0,tmp1,tmp2,tmp3,tmp4,cnt1)
tri_adder:
	movwf	tmp0
	clrf	tmp4
	movlw	3
	movwf	cnt1
	movf	F_reg,w
	andlw	b'00110000'
	movwf	tmp1
tri_add_loop:
	movf	tmp0,w
	andlw	b'00110000'
	movwf	tmp2
	bcf	STATUS,C
	rrf	tmp2,f
	rrf	tmp2,w
	iorwf	tmp1,f
	movf	A_reg,w
	andlw	b'00110000'
	movwf	tmp2
	swapf	tmp2,w
	iorwf	tmp1,w
	call	tri_add_3trits
	movwf	tmp3
	andlw	b'00000011'
	iorwf	tmp4,f
	movf	tmp3,w
	andlw	b'00001100'
	movwf	tmp1
	rlf	tmp1,f
	rlf	tmp1,f
	decfsz	cnt1,f
	goto	tri_add_next
	movf	F_reg,w
	andlw	b'00001111'
	iorwf	tmp1,w
	movwf	F_reg
	movf	tmp4,w
	movwf	A_reg
	return
tri_add_next:
	rlf	tmp4,f
	rlf	tmp4,f
	rlf	tmp0,f
	rlf	tmp0,f
	rlf	A_reg,f
	rlf	A_reg,f
	goto	tri_add_loop

; Ternary inversion (negation) of W (used tmp0,tmp4)
tri_neg: ; 14 cycles with call
	movwf	tmp0
	andlw	b'01010101'
	movwf	tmp4
	movf	tmp0,w
	andlw	b'10101010'
	movwf	tmp0
	bcf	STATUS,C
	rlf	tmp4,f
	rrf	tmp0,w
	iorwf	tmp4,w
	return
; P.S. it also works with inverted binary representation

; Ternary increment of W, C if overflow (used tmp4)
tri_inc:
	bcf	STATUS,C
	movwf	tmp4
tri_i5:	btfss	tmp4,5
	goto	tri_i4
	bcf	tmp4,5
	bsf	tmp4,4
	goto	tri_i3
tri_i4:	btfss	tmp4,4
	bsf	tmp4,5
	bcf	tmp4,4
	movf	tmp4,w
	return
tri_i3:	btfss	tmp4,3
	goto	tri_i2
	bcf	tmp4,3
	bsf	tmp4,2
	goto	tri_i1
tri_i2:	btfss	tmp4,2
	bsf	tmp4,3
	bcf	tmp4,2
	movf	tmp4,w
	return
tri_i1:	btfss	tmp4,1
	goto	tri_i0
	bcf	tmp4,1
	bsf	tmp4,0
	goto	tri_ic
tri_i0:	btfss	tmp4,0
	bsf	tmp4,1
	bcf	tmp4,0
	movf	tmp4,w
	return
tri_ic: movf	tmp4,w
	bsf	STATUS,C
	return

; Ternary increment of 9-trit PC
tri_inc_pc3:
	movf	PC_l,w
	call	tri_inc
	movwf	PC_l
	btfss	STATUS,C
	return
	movf	PC_m,w
	call	tri_inc
	movwf	PC_m
	btfss	STATUS,C
	return
	movf	PC_h,w
	call	tri_inc
	movwf	PC_h
	btfss	STATUS,C
	return
	bsf	Mode,0
	return

; Read one triad from the address stored in 3 triads started from FSR and save result to W
tri_read:
; skip middle address for now...
	movf	INDF,w
	subwf	DA_h,w
	btfss	STATUS,Z
	goto	tri_read_
tri_read_ram:
	incf	FSR,f
	incf	FSR,f
	movf	INDF,w
	addlw	0x40
	movwf	FSR
	movf	INDF,w
	return
tri_read_:
	movf	INDF,w
	subwf	CA_h,w
	btfss	STATUS,Z
	goto	tri_read_zero
tri_read_eep:
	incf	FSR,f
	incf	FSR,f
	movf	INDF,w
	call	eeprom_read
	bcf STATUS,RP0
	bcf STATUS,RP1
	return
tri_read_zero: ; don't fail if outsize of the address range
	clrw
	return

; Write one triad W to the address stored in 3 triads started from FSR (used tmp0)
tri_write:
; skip middle address for now...
	movwf	tmp0
	movf	INDF,w
	subwf	DA_h,w
	btfss	STATUS,Z
	return;goto	tri_write_; ignore if not DATA
tri_write_ram:
	incf	FSR,f
	incf	FSR,f
	movf	INDF,w
	addlw	0x40
	movwf	FSR
	movf	tmp0,w
	movwf	INDF
	return
;tri_write_:
;	movf	INDF,w
;	subwf	CA_h,w
;	btfss	STATUS,Z
;	goto	tri_fail
;tri_write_eep:
;	incf	FSR,f
;	incf	FSR,f
;	movf	tmp0,w
;	movwf	eeprom_write_value
;	movf	INDF,w
;	goto	eeprom_write ; return will be invoked from eeprom_write

; Set current DP in FSR register
tri_cur_dp:
	btfss	F_reg,2
	goto	tri_cur_dp0
	movlw	DPn_h
	goto	tri_cur_dp_
tri_cur_dp0:
	btfsc	F_reg,3
	goto	tri_cur_dp1
	movlw	DPo_h
	goto	tri_cur_dp_
tri_cur_dp1:
	movlw	DPp_h
tri_cur_dp_:
	movwf	FSR
	return

; Set RSF (higher trit of the register F) based of the sign of the value in the register A
tri_rsf:
	btfsc	A_reg,0
	goto	tri_rsf_p
	btfsc	A_reg,1
	goto	tri_rsf_n
	btfsc	A_reg,2
	goto	tri_rsf_p
	btfsc	A_reg,3
	goto	tri_rsf_n
	btfsc	A_reg,4
	goto	tri_rsf_p
	btfsc	A_reg,5
	goto	tri_rsf_n
tri_rsf_o:
	bcf	F_reg,0
	bcf	F_reg,1
	return
tri_rsf_n:
	bsf	F_reg,0
	bcf	F_reg,1
	return
tri_rsf_p:
	bcf	F_reg,0
	bsf	F_reg,1
	return

; Read 1 immediate triad and save it in tmp0
tri_read1pc:
	movlw	PC_h
	movwf	FSR
	call	tri_read
	movwf	tmp0
	goto	tri_inc_pc3 ; return will be invoked from tri_inc_pc3

; Read 3 immediate triads and save them in tmp1,tmp2,tmp3
tri_read3pc:
	movlw	PC_h
	movwf	FSR
	call	tri_read
	movwf	tmp1
	call	tri_inc_pc3
	movlw	PC_h
	movwf	FSR
	call	tri_read
	movwf	tmp2
	call	tri_inc_pc3
	movlw	PC_h
	movwf	FSR
	call	tri_read
	movwf	tmp3
	goto	tri_inc_pc3 ; return will be invoked from tri_inc_pc3

; Jump to tmp1,tmp2,tmp3
tri_jump:
	movlw	PC_h
	movwf	FSR
; Move tmp1,tmp2,tmp3 to 3 registers started with FSR
tri_tmp3ind:
	movf	tmp1,w
	movwf	INDF
	incf	FSR,f
	movf	tmp2,w
	movwf	INDF
	incf	FSR,f
	movf	tmp3,w
	movwf	INDF
	return

; Perform OPA command on A_reg with code tmp0 and save result in tmp1 (used cnt1)
tri_opa:
	movlw	3
	movwf	cnt1
	clrf	tmp1
tri_opa_:
	btfss	A_reg,0
	goto	tri_opa1
	btfsc	tmp0,0
	bsf	tmp1,6
	btfsc	tmp0,1
	bsf	tmp1,7
	goto	tri_opa_loop
tri_opa1:
	btfss	A_reg,1
	goto	tri_opa0
	btfsc	tmp0,4
	bsf	tmp1,6
	btfsc	tmp0,5
	bsf	tmp1,7
	goto	tri_opa_loop
tri_opa0:
	btfsc	tmp0,2
	bsf	tmp1,6
	btfsc	tmp0,3
	bsf	tmp1,7
tri_opa_loop:
	bcf	STATUS,C
	rrf	tmp1,f
	rrf	tmp1,f
	rrf	A_reg,f
	rrf	A_reg,f
	decfsz	cnt1,f
	goto	tri_opa_
	return

; Perform OPB command on A_reg and B_reg with code tmp1,tmp2,tmp3 and save result in tmp0 (used tmp4,cnt1)
tri_opb:
	movf	tmp1,w
	movwf	tmp4
	movf	tmp3,w
	movwf	tmp0
	call	tri_opa
	movf	tmp1,w
	movwf	tmp3
	movf	tmp2,w
	movwf	tmp0
	call	tri_opa
	movf	tmp1,w
	movwf	tmp2
	movf	tmp4,w
	movwf	tmp0
	call	tri_opa
	clrf	tmp0
	btfss	B_reg,0
	goto	tri_opb_h1
	btfsc	tmp1,0
	bsf	tmp0,0
	btfsc	tmp1,1
	bsf	tmp0,1
	goto	tri_opb_m
tri_opb_h1:
	btfsc	B_reg,1
	goto	tri_opb_h0
	btfsc	tmp3,0
	bsf	tmp0,0
	btfsc	tmp3,1
	bsf	tmp0,1
	goto	tri_opb_m
tri_opb_h0:
	btfsc	tmp2,0
	bsf	tmp0,0
	btfsc	tmp2,1
	bsf	tmp0,1
tri_opb_m:
	btfss	B_reg,2
	goto	tri_opb_m1
	btfsc	tmp1,2
	bsf	tmp0,2
	btfsc	tmp1,3
	bsf	tmp0,3
	goto	tri_opb_l
tri_opb_m1:
	btfsc	B_reg,3
	goto	tri_opb_m0
	btfsc	tmp3,2
	bsf	tmp0,2
	btfsc	tmp3,3
	bsf	tmp0,3
	goto	tri_opb_l
tri_opb_m0:
	btfsc	tmp2,2
	bsf	tmp0,2
	btfsc	tmp2,3
	bsf	tmp0,3
tri_opb_l:
	btfss	B_reg,4
	goto	tri_opb_l1
	btfsc	tmp1,4
	bsf	tmp0,4
	btfsc	tmp1,5
	bsf	tmp0,5
	return
tri_opb_l1:
	btfsc	B_reg,5
	goto	tri_opb_l0
	btfsc	tmp3,4
	bsf	tmp0,4
	btfsc	tmp3,5
	bsf	tmp0,5
	return
tri_opb_l0:
	btfsc	tmp2,4
	bsf	tmp0,4
	btfsc	tmp2,5
	bsf	tmp0,5
	return

; Perform single step of the program
tri_step:
	call	tri_inc_pc3
	btfss	C_reg,0
	goto tri_step0
	; Nxx
	btfss	C_reg,2
	goto	tri_step_0
	; NNx
	btfss	C_reg,4
	goto	tri_step__0
	; NNN (-13) SAN
	movlw	DPn_h
	movwf	FSR
	movf	A_reg,w
	goto	tri_write ; return will be invoked from tri_write
tri_step__0:
	btfsc	C_reg,5
	goto	tri_step__1
	; NNO (-12) SAO
	movlw	DPo_h
	movwf	FSR
	movf	A_reg,w
	goto	tri_write ; return will be invoked from tri_write
tri_step__1:
	; NNP (-11) SAP
	movlw	DPp_h
	movwf	FSR
	movf	A_reg,w
	goto	tri_write ; return will be invoked from tri_write
tri_step_0:
	btfsc	C_reg,3
	goto	tri_step_1
	; NOx
	btfss	C_reg,4
	goto	tri_step_00
	; NON (-10) SAF
	movf	A_reg,w
	movwf	F_reg
	return
tri_step_00:
	btfsc	C_reg,5
	goto	tri_step_01
	; NOO (-9) SPCD
	call	tri_cur_dp
	movf	PC_h,w
	movwf	INDF
	incf	FSR,f
	movf	PC_m,w
	movwf	INDF
	incf	FSR,f
	movf	PC_l,w
	movwf	INDF
	return
tri_step_01:
	; NOP (-8) SAB
	movf	A_reg,w
	movwf	B_reg
	return
tri_step_1:
	; NPx
	btfss	C_reg,4
	goto	tri_step_10
	; NPN (-7) SAL
	call	tri_cur_dp
	goto	tri_step_sal
tri_step_10:
	btfsc	C_reg,5
	goto	tri_step_11
	; NPO (-6) SAM
	call	tri_cur_dp
	goto	tri_step_sam
tri_step_11:
	; NPP (-5) SAH
	call	tri_cur_dp
	goto	tri_step_sah
tri_step_sal:
	incf	FSR,f
tri_step_sam:
	incf	FSR,f
tri_step_sah:
	movf	A_reg,w
	movwf	INDF
	return
tri_step0:
	btfsc	C_reg,1
	goto	tri_step1
	; Oxx
	btfss	C_reg,2
	goto	tri_step00
	; ONx
	btfss	C_reg,4
	goto	tri_step0_0
	; ONN (-4) RLA
	bcf	STATUS,C
	rlf	A_reg,f
	rlf	A_reg,f
	btfsc	F_reg,5
	bsf	A_reg,1
	btfsc	F_reg,4
	bsf	A_reg,0
	bcf	F_reg,5
	btfsc	A_reg,7
	bsf	F_reg,5
	bcf	A_reg,7
	bcf	F_reg,4
	btfsc	A_reg,6
	bsf	F_reg,4
	bcf	A_reg,6
	goto	tri_rsf ; return will be invoked from tri_rsf
tri_step0_0:
	btfsc	C_reg,5
	goto	tri_step0_1
	; ONO (-3) ADD
	movf	B_reg,W
	call	tri_adder
	goto	tri_rsf ; return will be invoked from tri_rsf
tri_step0_1:
	; ONP (-2) RRA
	btfsc	F_reg,5
	bsf	A_reg,7
	btfsc	F_reg,4
	bsf	A_reg,6
	bcf	STATUS,C
	rrf	A_reg,f
	btfsc	STATUS,C
	bsf	F_reg,4
	bcf	STATUS,C
	rrf	A_reg,f
	btfsc	STATUS,C
	bsf	F_reg,5
	goto	tri_rsf ; return will be invoked from tri_rsf
tri_step00:
	btfsc	C_reg,3
	goto	tri_step01
	; OOx
	btfss	C_reg,4
	goto	tri_step000
	; OON (-1) LAI #
	call	tri_read1pc
	movf	tmp0,w
	movwf	A_reg
	return
tri_step000:
	btfsc	C_reg,5
	goto	tri_step001
	; OOO (0) ADI #
	call	tri_read1pc
	movf	tmp0,w
	call	tri_adder
	goto	tri_rsf ; return will be invoked from tri_rsf
tri_step001:
	; OOP (1) OPA #
	call	tri_read1pc
	call	tri_opa
	movf	tmp1,w
	movwf	A_reg
	goto	tri_rsf ; return will be invoked from tri_rsf
tri_step01:
	; OPx
	btfss	C_reg,4
	goto	tri_step010
	; OPN (2) LDI # # #
	call	tri_read3pc
	call	tri_cur_dp
	goto	tri_tmp3ind ; return will be invoked from tri_tmp3ind
tri_step010:
	btfsc	C_reg,5
	goto	tri_step011
	; OPO (3) JMP # # #
	call	tri_read3pc
	goto	tri_jump ; return will be invoked from tri_jump
tri_step011:
	; OPP (4) OPB # # #
	call	tri_read3pc
	call	tri_opb
	movf	tmp0,w
	movwf	A_reg
	goto	tri_rsf ; return will be invoked from tri_rsf
tri_step1:
	; Pxx
	btfss	C_reg,2
	goto	tri_step10
	; PNx
	btfss	C_reg,4
	goto	tri_step1_0
	; PNN (5) LAN
	movlw	DPn_h
	movwf	FSR
	call	tri_read
	movwf	A_reg
	return
tri_step1_0:
	btfsc	C_reg,5
	goto	tri_step1_1
	; PNO (6) LAO
	movlw	DPo_h
	movwf	FSR
	call	tri_read
	movwf	A_reg
	return
tri_step1_1:
	; PNP (7) LAP
	movlw	DPp_h
	movwf	FSR
	call	tri_read
	movwf	A_reg
	return
tri_step10:
	btfsc	C_reg,3
	goto	tri_step11
	; POx
	btfss	C_reg,4
	goto	tri_step100
	; PON (8) LAF
	movf	F_reg,w
	movwf	A_reg
	return
tri_step100:
	btfsc	C_reg,5
	goto	tri_step101
	; POO (9) LPCD
	call	tri_cur_dp
	movf	INDF,w
	movwf	PC_h
	incf	FSR,f
	movf	INDF,w
	movwf	PC_m
	incf	FSR,f
	movf	INDF,w
	movwf	PC_l
	return
tri_step101:
	; POP (10) LAB
	movf	B_reg,w
	movwf	A_reg
	return
tri_step11:
	; NPx
	btfss	C_reg,4
	goto	tri_step110
	; PPN (11) LAL
	call	tri_cur_dp
tri_step_lal:
	incf	FSR,f
tri_step_lam:
	incf	FSR,f
tri_step_lah:
	movf	INDF,w
	movwf	A_reg
	return
tri_step110:
	btfsc	C_reg,5
	goto	tri_step111
	; PPO (12) LAM
	call	tri_cur_dp
	goto	tri_step_lam
tri_step111:
	; PPP (13) LAH
	call	tri_cur_dp
	goto	tri_step_lah

tri_read_switch:
	movf	swit0,w
	call	tri_neg
	movwf	tmp1
	movf	swit1,w
	call	tri_neg
	movwf	tmp2
	movf	swit2,w
	call	tri_neg
	movwf	tmp3
	movlw	tmp1
	movwf	FSR
	return

; Serial print triad from W (used tmp0, cnt1)
;print_triad:
;	movwf	tmp0
;	movlw	3
;	movwf	cnt1
;ptriad:	btfsc	tmp0,0
;	goto	ptriadn
;	btfsc	tmp0,1
;	goto	ptriadp
;	_serial_send_ 'O'
;	goto ptriad1
;ptriadp:
;	_serial_send_ 'P'
;	goto ptriad1
;ptriadn:
;	_serial_send_ 'N'
;ptriad1:
;	rrf	tmp0,f
;	rrf	tmp0,f
;	decfsz	cnt1,f
;	goto	ptriad
;	return

;_print_triad MACRO T
;	movf	T,w
;	call	print_triad
;	_serial_print_nl
;	ENDM

;_print_triad_ MACRO T
;	movlw	T
;	call	print_triad
;	_serial_print_nl
;	ENDM

Main:

; Initialize registers

	movlw	Mode
	movwf	FSR
	movlw	52
	movwf	count
InitRegs:
	clrf	INDF
	incf	FSR,f
	decfsz	count,f
	goto	InitRegs

	movlw	b'00011000' ; OPN
	movwf	DA_h
	movlw	b'00010101' ; NNN
	movwf	DA_m

;	movlw	0xA0
;	movwf	FSR
;	movlw	9
;	movwf	count
;InitRegs2:
;	clrf	INDF
;	incf	FSR,f
;	decfsz	count,f
;	goto	InitRegs2

;	clrf	tmp0
;	movlw	48
;	movwf	count
;InitEeprom:
;	_eeprom_write_a tmp0,0x14
;	incf	tmp0,f
;	decfsz	count,f
;	goto	InitEeprom

;	clrf	PC_h
;	clrf	PC_m
;	clrf	PC_l
;	clrf	Mode

;	bcf	PORTA,5 ; fire LED

; Main loop

loop: ; ~X+35 (+7uS) per instruction
	movlw	b'11111110'
	movwf	mask
	movlw	5
	movwf	count
loop0:
	movf	mask,w
	movwf	PORTA
	call	tri_switch ; 6 cycles
	movwf	FSR
	comf	PORTB,w
	movwf	INDF
	btfss	mask,0
	comf	PC_h,w
	btfss	mask,1
	comf	PC_m,w
	btfss	mask,2
	comf	PC_l,w
	btfsc	mask,3
	goto	loop00
	movlw	PC_h
	movwf	FSR
	call	tri_read
	movwf	C_reg
	comf	C_reg,w
	btfsc	swit4,0
	comf	D_reg,w
	btfsc	swit4,1
	comf	D_reg,w
loop00:	btfss	mask,4
	comf	A_reg,w
	movwf	PORTC
	btfss	swit4,5 ; check "go" mode
	goto	loop5 ; delay if not "go"
	call	tri_step ; X cycles
loop01:	movlw	b'11111111'
	movwf	PORTC ; clear current LEDs
	bsf	STATUS,C
	rlf	mask,f
	decfsz	count,f
	goto	loop0

	btfss	swit4,4 ; check switch set 4 in state S (step)
	goto	l1 ; go next if not
	; step mode
	btfsc	Mode,1 ; check if mode "step" is not yet set
	goto	loop ; go to beginning if "step" is already set
	bsf	Mode,1 ; set mode "step"
	call	tri_step ; perform a single step
	goto	loop ; go to beginning
l1:	bcf	Mode,1 ; clear mode "step"
	btfss	swit4,2 ; check switch set 4 in state I (interrupt)
	goto	l2 ; go next if not
	; interrupt mode
	btfsc	Mode,2 ; check if mode "interrupt" is not yet set
	goto	loop ; go to beginning if "interrupt" is already set
	bsf	Mode,2 ; set mode "interrupt"
	call	tri_read_switch ; read address from switches
	call	tri_jump ; perform jump to the new PC
	goto	loop ; go to beginning
l2:	bcf	Mode,2 ; clear mode "interrupt"
	; check read/write
	btfss	swit4,1 ; check switch set 4 in state R (read)
	goto	l3 ; go next if not
	; read mode (with repeats)
	btfsc	swit4,3 ;  check switch set 4 in state M (main)
	_PDBL ; hack for debugging - launch PDBLv1 interface if R and M are both set
	call	tri_read_switch ; read address from switches
	call	tri_read ; read value from memory with such address
	movwf	D_reg ; move this value to the register D
	goto	loop ; go to beginning
l3:	btfss	swit4,0 ; check switch set 4 in state W (write)
	goto	loop ; go to beginning if not
	; write mode (with repeats)
	movf	swit3,w ; read value from data switch
	call	tri_neg ; invert it
	movwf	D_reg ; move this value to the register D
	call	tri_read_switch ; read address from switches
	movf	D_reg,w ; move value to save to the accumulator
	call	tri_write ; write value to the memory
	goto	loop ; go to beginning
loop5:	_delay_us 20 ; delay 20uS - used above
	goto	loop01

	END
 